package cmd

import (
	"flag"
	"path/filepath"
	"strings"

	"cms/system/helper"
	"cms/system/vars"
)

type (
	MapStr  = vars.MapStr
	MMapStr = vars.MMapStr
	MapAny  = vars.MapAny
)

const (
	ModelName      = "model"
	ServiceName    = "service"
	ValidateName   = "validate"
	ControllerName = "controller"
	DS             = string(filepath.Separator)
)

var (
	dry     = helper.Dry
	trim    = helper.Trim
	join    = helper.Join
	empty   = helper.Empty
	appRoot = helper.GetRoot
	ucfirst = helper.UcFirst

	Group = "admin"
)

func Parser() *CmdParam {
	var (
		pid       int    // 菜单上级
		name      string // 生成的菜单名称
		table     string // 要想创建的表名，记住，不要带表前缀
		field     string // 要在列表里显示的字段，没有指定则根据表里的字段注释进行解析，没有注释的则显示字段名称
		paths     string // 想要解析的项目路径，一般项目路径下都会有数据库配置信息，因此不需要单独配置数据库信息
		suffix    string
		hasModel  bool // 是否生成模型
		onlyIndex bool
	)

	flag.StringVar(&name, "n", "默认管理", "该功能名称，5个字以内")
	flag.StringVar(&paths, "p", "", "要解析项目的路径")
	flag.StringVar(&suffix, "s", "", "命名空间后缀")
	flag.StringVar(&table, "t", "", "表名")
	flag.BoolVar(&hasModel, "hm", false, "是否要生成数据表模型")
	flag.BoolVar(&onlyIndex, "oi", false, "是否只生成记录")
	flag.StringVar(&field, "f", "", "列表里显示以逗号分割的字段，例如：id=ID,name=名称:require,cate=分类:require")
	flag.StringVar(&Group, "g", "admin", "模块，默认为admin")
	flag.IntVar(&pid, "pid", 0, "上级菜单id，没有的话就创建主菜单")
	flag.Parse()

	if empty(paths) {
		paths = appRoot()
	}

	if empty(table) {
		dry("请你提供一个数据表名")
	}

	table = strings.ToLower(trim(table))

	// 列表显示字段
	fieldMap := parseField(field)
	htmlPrefix := parseHTMLPrefix(table)
	JsPrefix := parseApiJsPrefix(table)

	// 模型命名空间处理
	modelClass := handleNamespace(table, ModelName, false, suffix)
	controllerClass := handleNamespace(table, ControllerName, false, suffix)
	serviceClass := handleNamespace(table, ServiceName, false, suffix)
	validate := handleNamespace(table, ValidateName, false, suffix)

	model := handleNamespace(table, ModelName, true, suffix)
	controller := handleNamespace(table, ControllerName, true, suffix)
	service := handleNamespace(table, ServiceName, true, suffix)

	return &CmdParam{
		Name:      name,
		Path:      paths,
		Suffix:    suffix,
		Table:     table,
		Field:     fieldMap,
		HasModel:  hasModel,
		OnlyIndex: onlyIndex,
		Group:     Group,
		NameSpace: &NameSpace{
			Controller: controller,
			Model:      model,
			Service:    service,
			Validate:   validate,
		},
		AppPath: &AppPath{
			Controller: paths + DS + controller,
			Validate:   paths + DS + validate,
			Service:    paths + DS + service,
			Model:      paths + DS + model,
		},
		AppClass: &AppClass{
			Controller:   controllerClass,
			ValidateAdd:  validate + DS + "Add",
			ValidateEdit: validate + DS + "Edit",
			Service:      serviceClass,
			Model:        modelClass,
		},
		HTMLUri: htmlPrefix,
		JsUri:   JsPrefix,
		Pid:     pid,
	}
}

func parseField(field string) MMapStr {
	fieldMap := make(MMapStr)
	if !empty(field) {
		field = trim(field)
		arr := strings.Split(field, ",")
		for _, val := range arr {
			tmp := strings.Split(val, "=")
			id := ""
			name := ""
			require := "false"
			if len(tmp) == 1 {
				id = tmp[0]
				name = tmp[0]
			} else {
				id = tmp[0]
				name = tmp[1]
			}

			if ridx := strings.Index(name, ":require"); ridx > 0 {
				require = "true"
				name = name[:ridx]
			}
			id = strings.Trim(id, " ")
			fieldMap[id] = map[string]string{
				"id":      id,
				"name":    strings.Trim(name, " "),
				"require": require,
			}
		}
	}

	return fieldMap
}

func parseHTMLPrefix(table string) string {
	temp := []string{Group}
	if strings.Index(table, "_") > 0 {
		temp = append(temp, strings.Split(table, "_")...)
	} else {
		temp = append(temp, table)
	}

	return "/" + join("/", temp...) + "/"
}

func parseApiJsPrefix(table string) string {
	temp := []string{Group}
	if strings.Index(table, "_") > 0 {
		temp = append(temp, strings.Split(table, "_")...)
	} else {
		temp = append(temp, table)
	}

	return "/" + join(".", temp...) + "/"
}

func handleNamespace(table, ctype string, only bool, suffixs ...string) string {
	suffix := ""
	if len(suffixs) > 0 && suffixs[0] != "" {
		suffix = suffixs[0]
	}

	nameSpace := []string{"app", ctype, Group}
	if empty(suffix) { // 没有传递命名空间后缀的话
		if strings.Index(table, "_") > 0 {
			tableArr := strings.Split(table, "_")
			if ctype == "controller" || ctype == "model" || ctype == "service" {
				lastElem := tableArr[len(tableArr)-1]
				tableArr[len(tableArr)-1] = ucfirst(lastElem)
			}
			nameSpace = append(nameSpace, tableArr...)
		} else {
			if ctype == "controller" || ctype == "model" || ctype == "service" {
				nameSpace = append(nameSpace, ucfirst(table))
			} else {
				nameSpace = append(nameSpace, table)
			}
		}
	} else {
		if strings.Index(suffix, "\\") > 0 {
			if suffix[:3] == "app" {
				nameSpace = strings.Split(suffix, "\\")
			} else {
				suffix = strings.ToLower(suffix)
				suffixArr := strings.Split(suffix, "\\")
				if ctype == "controller" || ctype == "model" || ctype == "service" {
					lastElem := suffixArr[len(suffixArr)-1]
					suffixArr[len(suffixArr)-1] = ucfirst(lastElem)
				}
				nameSpace = append(nameSpace, suffixArr...)
			}
		} else {
			if ctype == "controller" || ctype == "model" || ctype == "service" {
				nameSpace = append(nameSpace, ucfirst(table))
			} else {
				nameSpace = append(nameSpace, table)
			}
		}
	}

	if ctype == "model" {
		nameSpace[2] = "admin"
	}

	if only && ctype != "validate" {
		nameSpace = nameSpace[:len(nameSpace)-1]
	}

	return join("\\", nameSpace...)
}
